//
//  AppleScript.m
//  Pennyworth
//
//  Created by Chris Karr on 1/27/08.
//  Copyright 2008 Chris J. Karr. All rights reserved.
//

#import "AppleScriptSensor.h"
#import "Context.h"
#import <Carbon/Carbon.h>

#define SCRIPT_PATH [NSString stringWithFormat:@"%@/Library/Application Support/Pennyworth/AppleScript/Sensors", NSHomeDirectory ()]
#define OSASCRIPT_PATH @"/usr/bin/osascript"
#define REFRESH_SCRIPTS 300
#define REFRESH 1
#define DEFAULT_REFRESH 30

#define UPDATE_INTERVAL_KEY @"Script Update Interval"
#define LAST_UPDATE_KEY @"Script Last Update"
#define IDENTIFIER_KEY @"Script Identifier"

@implementation AppleScriptSensor

- (void) awakeFromNib
{
	scripts = [[NSMutableDictionary alloc] init];

	timer = [[NSTimer scheduledTimerWithTimeInterval:REFRESH_SCRIPTS target:self selector:@selector(refreshScripts:) userInfo:nil repeats:YES] retain];
	[timer fire];

	callTimer = [[NSTimer scheduledTimerWithTimeInterval:REFRESH target:self selector:@selector(callScripts:) userInfo:nil repeats:YES] retain];
}

- (void) callScripts:(NSTimer *) theTimer
{
	NSDate * now = [NSDate date];
	NSArray * runningApps = [[NSWorkspace sharedWorkspace] launchedApplications];
	
	for (NSString * path in [scripts allKeys])
	{
		NSMutableDictionary * script = [scripts valueForKey:path];

		BOOL running = NO;
		
		NSString * scriptIdentifier = [script valueForKey:IDENTIFIER_KEY];
		
		if (scriptIdentifier != nil)
		{
			for (NSDictionary * app in runningApps)
			{
				if ([[app valueForKey:@"NSApplicationBundleIdentifier"] isEqual:scriptIdentifier])
					running = YES;
			}
		}
		else
			running = YES;
	
		NSDate * lastUpdate = [script valueForKey:LAST_UPDATE_KEY];
		
		if (lastUpdate == nil)
			lastUpdate = [NSDate distantPast];
		
		NSNumber * updateInterval = [script valueForKey:UPDATE_INTERVAL_KEY];
		
		if ([now timeIntervalSinceDate:lastUpdate] > [updateInterval doubleValue] && running)
		{
			[NSTask launchedTaskWithLaunchPath:OSASCRIPT_PATH arguments:[NSArray arrayWithObject:path]];
			[script setValue:now forKey:LAST_UPDATE_KEY];
		}
	}
}

- (void) refreshScripts:(NSTimer *) theTimer
{
	[scripts removeAllObjects];
	
	NSFileManager * fm = [NSFileManager defaultManager];
	BOOL isDir = NO;
	
	if ([fm fileExistsAtPath:SCRIPT_PATH isDirectory:&isDir] && isDir)
	{
		NSArray * files = [[fm directoryContentsAtPath:SCRIPT_PATH] sortedArrayUsingSelector:@selector(compare:)];
		
		for (NSString * file in files)
		{
			if ([file hasSuffix:@".scpt"])
			{
				NSMutableDictionary * scriptOptions = [scripts valueForKey:[NSString stringWithFormat:@"%@/%@", SCRIPT_PATH, file]];

				if (scriptOptions == nil)
				{
					scriptOptions = [NSMutableDictionary dictionary];
					
					NSDictionary * errors = nil;
					NSURL * scriptUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", SCRIPT_PATH, file]];
					
					NSAppleScript * scpt = [[NSAppleScript alloc] initWithContentsOfURL:scriptUrl error:&errors];
					
					if (scpt != nil)
					{
						if ([scpt compileAndReturnError:&errors])
						{
							ProcessSerialNumber psn = { 0, kCurrentProcess };
							NSAppleEventDescriptor * target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber
																											 bytes:&psn
																											length:sizeof(ProcessSerialNumber)];

							NSAppleEventDescriptor * handler = [NSAppleEventDescriptor descriptorWithString:@"get_interval"];

							NSAppleEventDescriptor * event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
																									  eventID:kASSubroutineEvent
																							 targetDescriptor:target
																									 returnID:kAutoGenerateReturnID
																								transactionID:kAnyTransactionID];

							[event setParamDescriptor:handler forKeyword:keyASSubroutineName];

							NSAppleEventDescriptor * results = [scpt executeAppleEvent:event error:&errors];
						
							if (results != nil)
								[scriptOptions setValue:[NSNumber numberWithInt:[results int32Value]] forKey:UPDATE_INTERVAL_KEY];
							else
								[scriptOptions setValue:[NSNumber numberWithInt:DEFAULT_REFRESH] forKey:UPDATE_INTERVAL_KEY];

							handler = [NSAppleEventDescriptor descriptorWithString:@"get_identifier"];

							event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
																			 eventID:kASSubroutineEvent
																	targetDescriptor:target
																			returnID:kAutoGenerateReturnID
																	   transactionID:kAnyTransactionID];

							[event setParamDescriptor:handler forKeyword:keyASSubroutineName];

							results = [scpt executeAppleEvent:event error:&errors];

							if (results != nil)
								[scriptOptions setValue:[results stringValue] forKey:IDENTIFIER_KEY];

							[scpt release];
						}
					}

					[scripts setValue:scriptOptions forKey:[NSString stringWithFormat:@"%@/%@", SCRIPT_PATH, file]];
				}
			}
		}
	}
	else
		[fm createDirectoryAtPath:SCRIPT_PATH withIntermediateDirectories:YES attributes:nil error:nil];
}

@end
